<?php
/**
 * 微信支付相关
 * Created by PhpStorm.
 */
namespace Pament;

use aliwappay\wappay\buildermodel\AlipayTradeWapPayContentBuilder;
use aliwappay\wappay\service\AlipayTradeService;
use app\common\exception\ApiException;
use app\model\AfterSales;
use app\model\ReachOrder;
use app\model\ScOrder;
use app\util\Tools;
use think\Cache;
use think\Db;
use think\Log;

class wxPament {

    //微信提现配置 （依赖微信商户后台配置）
    static $WECHAT_PAY_CONFIG = [
        'max_times' => 2,         //每天每个用户的提现次数
        'max_amount' => 500,  //单次提现最大额度（单位：元）
        'min_amount' => 1     //单次提现最小额度 （单位：元）
    ];

    /**
     * app支付
     */
    public function appPament($out_trade_no, $money, $trade_type = 'APP', $body = '甜豆 充值',$Mall = 0) {
        $spbill_create_ip = Tools::get_client_ip();     //获得用户设备 IP
        $options = [
            'appid'            => config('pament.wechat_app_appid'),
            'mch_id'           => config('pament.wechat_mchid'),
            'out_trade_no'     => $out_trade_no,
            'nonce_str'        => Tools::token_create(),
            'body'             => $body,
            'total_fee'        => (int)$money,
            'spbill_create_ip' => $spbill_create_ip,
            'notify_url'       => config('pament.wechat_app_notify_url'),
            'trade_type'       => $trade_type
        ];
        if(config('app_debug') == true) {
            $options['total_fee'] = 1;
            $options['body'] = "技术部测试";
        }


        //扫码支付回调地址修改
        if ($trade_type === 'NATIVE') {
            $options['product_id'] = $out_trade_no;
            $options['notify_url'] = config('pament.wechat_native_notify_url');
        }

        //扫码支付回调地址修改
        if ($Mall == '1') {
            $options['mch_id'] = config('pament.wechat_mchids');
            $options['notify_url'] = config('pament.wechat_app_mall_url');
        }
        $options['sign'] = Tools::wxSign($options,$Mall);

        $options = Tools::arrayToXml($options);

        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信传参地址

        $res = Tools::curlPost($url, $options);
        $res = Tools::xmltoarray($res);
        return $res;
    }


    /**
     * 小程序充值
     */
    public function programPament($out_trade_no, $openid, $money,$Mall = 0) {
        $spbill_create_ip = Tools::get_client_ip();     //获得用户设备 IP
        $options = [
            'appid'            => config('pament.wechat_program_appid'),
            'mch_id'           => config('pament.wechat_mchid'),
            'out_trade_no'     => $out_trade_no,
            'nonce_str'        => Tools::token_create(),
            'body'             => '积分 充值',
            'total_fee'        => (int)$money,
            'spbill_create_ip' => $spbill_create_ip,
            'notify_url'       => config('pament.wechat_recharge_notify_url'),
            'openid' => $openid,
            'trade_type'       => 'JSAPI'
        ];
        if(config('app_debug') == true) {
            $options['total_fee'] = 1;
            $options['body'] = "技术部测试";
        }

        $options['sign'] = Tools::wxSign($options,$Mall);

        $options = Tools::arrayToXml($options);

        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信传参地址

        $res = Tools::curlPost($url, $options);
        $res = Tools::xmltoarray($res);
        return $res;
    }

    /**
     * 小程序充值
     */
    public function groupRechargePament($out_trade_no, $openid, $money,$Mall = 0) {
        $spbill_create_ip = Tools::get_client_ip();     //获得用户设备 IP
        $options = [
            'appid'            => config('pament.wechat_program_appid'),
            'mch_id'           => config('pament.wechat_mchid'),
            'out_trade_no'     => $out_trade_no,
            'nonce_str'        => Tools::token_create(),
            'body'             => '拼团余额 充值',
            'total_fee'        => (int)$money,
            'spbill_create_ip' => $spbill_create_ip,
            'notify_url'       => config('pament.wechat_group_recharge_order_notify_url'),
            'openid' => $openid,
            'trade_type'       => 'JSAPI'
        ];
        if(config('app_debug') == true) {
            $options['total_fee'] = 1;
            $options['body'] = "技术部测试";
        }

        $options['sign'] = Tools::wxSign($options,$Mall);

        $options = Tools::arrayToXml($options);

        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信传参地址

        $res = Tools::curlPost($url, $options);
        $res = Tools::xmltoarray($res);
        return $res;
    }

    /**
     * 小程序充值
     */
    public function programVipPament($out_trade_no, $openid, $money,$Mall = 0) {
        $spbill_create_ip = Tools::get_client_ip();     //获得用户设备 IP
        $options = [
            'appid'            => config('pament.wechat_program_appid'),
            'mch_id'           => config('pament.wechat_mchid'),
            'out_trade_no'     => $out_trade_no,
            'nonce_str'        => Tools::token_create(),
            'body'             => '购买 添豆拼拼卡',
            'total_fee'        => (int)$money,
            'spbill_create_ip' => $spbill_create_ip,
            'notify_url'       => config('pament.wechat_vip_notify_url'),
            'openid' => $openid,
            'trade_type'       => 'JSAPI'
        ];
        if(config('app_debug') == true) {
            $options['total_fee'] = 1;
            $options['body'] = "技术部测试";
        }

        $options['sign'] = Tools::wxSign($options,$Mall);

        $options = Tools::arrayToXml($options);

        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信传参地址

        $res = Tools::curlPost($url, $options);
        $res = Tools::xmltoarray($res);
        return $res;
    }


    /**
     * 小程序充值
     */
    public function programGambleOrderPament($out_trade_no, $openid, $money,$Mall = 0) {
        $spbill_create_ip = Tools::get_client_ip();     //获得用户设备 IP
        $options = [
            'appid'            => config('pament.wechat_program_appid'),
            'mch_id'           => config('pament.wechat_mchid'),
            'out_trade_no'     => $out_trade_no,
            'nonce_str'        => Tools::token_create(),
            'body'             => '拼团订单',
            'total_fee'        => (int)$money,
            'spbill_create_ip' => $spbill_create_ip,
            'notify_url'       => config('pament.wechat_gamble_order_notify_url'),
            'openid' => $openid,
            'trade_type'       => 'JSAPI'
        ];
        if(config('app_debug') == true) {
            $options['total_fee'] = 1;
            $options['body'] = "技术部测试";
        }

        $options['sign'] = Tools::wxSign($options,$Mall);

        $options = Tools::arrayToXml($options);

        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信传参地址

        $res = Tools::curlPost($url, $options);
        $res = Tools::xmltoarray($res);
        return $res;
    }

    //小程序
    public function xcxPayOrder($order,$openID,$notifyType =1 )
    {

        $url = config('pament.wechat_program_notify_url');
        if ($notifyType == 2){
            $url = config('pament.wechat_program_notify_url_merge');
        }
        if ($notifyType == 3){
            $url = config('pament.wechat_program_notify_url_offline');
        }
        $prepayid = $this->xcxunifiedorder($order,$url,$openID,$notifyType);
        if ($prepayid !== false) {
            return $this->xcxcallPayParams($prepayid,$notifyType);
        } else {
            return [];
        }
    }

    //统一下单
    public function xcxunifiedorder($order,$notify_url,$openID,$type=1)
    {
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $appid = config('pament.wechat_program_appid');

        $requestData = [
            'appid'    => $appid,
            'mch_id'   => config('pament.wechat_mchids'),
            "nonce_str" => getRandom("32", "0123456789"),
            "sign" => "",
            "body" => $order["orderName"],
            "out_trade_no" => $order["tradeNo"],
            "total_fee" => $order["amount"]*100,
            "spbill_create_ip" => Tools::get_client_ip(),
            "notify_url" => $notify_url,
            "trade_type" => "JSAPI",
            "openid" => $openID
        ];
        if(config('app_debug') == true) {
            $requestData['total_fee'] = 1;
        }
        $mall = 1;
        $requestData["sign"] = $this->sign($requestData,$mall);

        $postStr = Tools::curlPost($url,$this->array2xml($requestData));
        if ($postStr) {
            $rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            Log::write("order: ".json_encode($rs), 'rechargePamentError');
            if ($rs["return_code"] == "SUCCESS") {
                return $rs["prepay_id"];
            } else {
                return  false;
            }
        } else {
            return  false;
        }

    }

    //调起支付接口参数
    public function xcxcallPayParams($prepayid,$type = 1)
    {
        $appid = config('pament.wechat_program_appid');
        $requestData = [
            "appId" => $appid,
            "timeStamp" => (string)time(),
            "nonceStr" => getRandom(32, "0123456789"),
            "package" => "prepay_id=".$prepayid,
            "signType" => "MD5"
        ];
        $mall = 1;
        $requestData["paySign"] = $this->sign($requestData,$mall);

        return $requestData;
    }

    //签名
    public function sign($data,$mall = 0)
    {
        $params = array();
        foreach ($data as $k => $v) {
            if (!empty($data[$k]) && $k != "sign") {
                $params[$k] = $v;
            }
        }
        ksort($params);
        $stringSignTemp = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if ($i == 0) {
                $stringSignTemp .= $k . "=" . $v;
            } else {
                $stringSignTemp .= "&" . $k . "=" . $v;
            }
            $i++;
        }
        if($mall == 1){
            $stringSignTemp .= "&key=" . config('pament.wechat_keys');
        }elseif ($mall == 2){
            $stringSignTemp .= "&key=" . config('pament.EE_wechat_key');
        }elseif ($mall == 3) {
            $stringSignTemp .= "&key=" . config('pament.wechat_tixian_key');
        } else {
            $stringSignTemp .= "&key=" . config('pament.wechat_key');
        }
        $sign = strtoupper(md5($stringSignTemp));
        return $sign;
    }



    public function array2xml($data){
        $xml = "<xml>";
        foreach($data as $k=>$v){
            $xml .= "<$k>".$v."</$k>";
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * TODO 微信申请退款操作
     * 重要变量：
     *      $order_sn = '2018000082009' 自己服务器的订单编号
     *      $refund_fee                 需要退款的金额 (例:10.50)
     *      $wxPayResultJsonRes         前期微信支付成功后回调保存的数据，
     *                                  原本在数据库中以 json字符串的形式保存，
     *                                  此处是取出后再 json_decode('xxxx',true)转化为了arr数组形式
     */
    public function payRefund($order_sn,$refund_fee){
        $config = config('pament');
        $orderModel = new ScOrder();
        //$wxPayResultJsonRes 请参考上面的介绍，自行获取
        $wxPayResultJsonRes = $orderModel->where(['tradeNo'=>$order_sn])->find();
        /*-----------------------------------------------------------------------------------*/
        if ($wxPayResultJsonRes && $refund_fee) {
            $out_trade_no = $wxPayResultJsonRes['tradeNo'];
            //$out_refund_no 商户退款单号 自定义而已
            $out_refund_no = $order_sn . 'refund' . time();
            $total_fee = $wxPayResultJsonRes['payMoney'];
            if(config('app_debug') == true) {
                $total_fee = 0.01;
                $refund_fee = 0.01;
            }
            //统一下单退款参数构造
            $unifiedorder = array(
                'appid' => $config['wechat_program_appid'],
                'mch_id' => $config['wechat_mchid'],
                'nonce_str' => getRandom(32, "0123456789"),
                'out_trade_no' => $out_trade_no,
                'out_refund_no' => $out_refund_no,
                'total_fee' => $total_fee * 100,
                'refund_fee' => intval(floatval($refund_fee) * 100),
            );
            $unifiedorder['sign'] = $this->sign($unifiedorder);
            $opUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
            //请求数据
            $postStr = $this->curl_post_ssl_refund($opUrl, $this->array2xml($unifiedorder));
            if ($postStr) {
                $rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                return $rs;
            } else {
                return false;
            }
        }
    }
    //---------------------------------------------------------------用到的函数------------------------------------------------------------
    /**
     * 此方法是为了进行 微信退款操作的 专属定制哦
     * (嘁，其实就是照搬了 人家官方的PHP Demo代码咯)
     *  尤其注意代码中涉及到的 "证书使用方式（二选一）"
     *  证书的路径要求为 服务器中的绝对路径[我的服务器为 CentOS6.5]
     *  证书是 在微信支付开发文档中有所提及，可自行获取保存
     */
    protected function curl_post_ssl_refund($url, $vars, $second=30,$aHeader=array())
    {
        $ch = curl_init();
        //超时时间
        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
        //这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
        //TODO 以下两种方式需选择一种

        /*------- --第一种方法，cert 与 key 分别属于两个.pem文件--------------------------------*/
        //默认格式为PEM，可以注释
//        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLCERT,__DIR__.DS.'apiclient_cert.pem');
        //默认格式为PEM，可以注释
//        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLKEY,__DIR__.DS.'apiclient_key.pem');

        //curl_setopt($ch, CURLOPT_CAINFO,'/mnt/www/Public/certxxxxxxxxxxxxxxxxxxxx755/rootca.pem');
        /*----------第二种方式，两个文件合成一个.pem文件----------------------------------------*/
        //curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
        if( count($aHeader) >= 1 ){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
        }
        curl_setopt($ch,CURLOPT_POST, 1);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$vars);
        $data = curl_exec($ch);
        if($data){
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            //echo "call faild, errorCode:$error\n";
            curl_close($ch);
            return false;
        }
    }

    /**
     * 此方法是为了进行 微信退款操作的 专属定制哦
     * (嘁，其实就是照搬了 人家官方的PHP Demo代码咯)
     *  尤其注意代码中涉及到的 "证书使用方式（二选一）"
     *  证书的路径要求为 服务器中的绝对路径[我的服务器为 CentOS6.5]
     *  证书是 在微信支付开发文档中有所提及，可自行获取保存
     */
    protected function tixian_curl_post_ssl($url, $vars, $second = 30, $aHeader = array())
    {
        $ch = curl_init();
        //超时时间
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        //这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        //TODO 以下两种方式需选择一种

        /*------- --第一种方法，cert 与 key 分别属于两个.pem文件--------------------------------*/
        //默认格式为PEM，可以注释
//        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
        curl_setopt($ch, CURLOPT_SSLCERT, __DIR__ . DS . 'apiclient_cert1.pem');
        //默认格式为PEM，可以注释
//        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch, CURLOPT_SSLKEY, __DIR__ . DS . 'apiclient_key1.pem');

        //curl_setopt($ch, CURLOPT_CAINFO,'/mnt/www/Public/certxxxxxxxxxxxxxxxxxxxx755/rootca.pem');
        /*----------第二种方式，两个文件合成一个.pem文件----------------------------------------*/
        //curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
        if (count($aHeader) >= 1) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
        }
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);
        $data = curl_exec($ch);
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            //echo "call faild, errorCode:$error\n";
            curl_close($ch);
            return false;
        }
    }

    /**
     * 重要变量：
     *      $order_sn = '2018000082009' 自己服务器的订单编号
     *      $refund_fee                 需要退款的金额 (例:10.50)
     */
    public function MallpayRefund($order_sn,$refund_fee,$out_refund_no = 0){
        $config = config('pament');
        $orderModel = new ReachOrder();

        $nonce_str = getRandom(32, "0123456789");
        if($out_refund_no == 0){
            $out_refund_no = substr($order_sn,11) . 'refund' . time();
        }
        $notify_url = config('pament.wechat_program_refund_notify_url');
        //$wxPayResultJsonRes 请参考上面的介绍，自行获取
        $wxPayResultJsonRes = $orderModel->where(['tradeNo'=>$order_sn])->find();
        /*-----------------------------------------------------------------------------------*/
        if ($wxPayResultJsonRes && $refund_fee) {
            $out_trade_no = $wxPayResultJsonRes['tradeNo'];
            //$out_refund_no 商户退款单号 自定义而已
            $total_fee = $wxPayResultJsonRes['payMoney'];
            if(config('app_debug') == true) {
                $total_fee = 0.01;
                $refund_fee = 0.01;
            }
            //统一下单退款参数构造
            $unifiedorder = array(
                'appid' => config('pament.wechat_program_appid'),
                'mch_id' => $config['wechat_mchids'],
                'nonce_str' => $nonce_str,
                'out_trade_no' => $out_trade_no,
                'out_refund_no' => $out_refund_no,
                'total_fee' => intval(Tools::bcCalculate($total_fee, 100,'*')),
                'refund_fee' => intval(Tools::bcCalculate(floatval($refund_fee),100,'*')),
                "notify_url" => $notify_url,
            );
            $unifiedorder['sign'] = $this->sign($unifiedorder,1);
            $opUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
            //请求数据
            $postStr = $this->curl_post_ssl_refund($opUrl, $this->array2xml($unifiedorder));
            if ($postStr) {
                $rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                return $rs;
            } else {
                return false;
            }
        }else{
            return false;
        }
    }

    /**
     * 重要变量：
     *      $order_sn = '2018000082009' 自己服务器的订单编号
     *      $refund_fee                 需要退款的金额 (例:10.50)
     */
    public function afterSalePayRefund($order_sn,$refund_fee){
        $config = config('pament');

        $nonce_str = getRandom(32, "0123456789");

        $out_refund_no = $order_sn;
        $notify_url = config('pament.after_sale_refund_notify_url');
        $Model = new AfterSales();
        $aftersales = $Model->where(['tradeNo'=>$order_sn])->find();

        $orderModel = new ReachOrder();
        $orderInfo = $orderModel->where(['orderID'=>$aftersales['orderID']])->find();

        if($aftersales['status'] != 0 || $aftersales['refundStatus'] != 0 || $orderInfo['status'] != 2){
            return false;
        }

        if ($aftersales && $refund_fee && $orderInfo) {
            $out_trade_no = $orderInfo['tradeNo'];
            $total_fee = $orderInfo['payMoney'];
            if(config('app_debug') == true) {
                $total_fee = 0.01;
                $refund_fee = 0.01;
            }
            //统一下单退款参数构造
            $unifiedorder = array(
                'appid' => config('pament.wechat_program_appid'),
                'mch_id' => $config['wechat_mchids'],
                'nonce_str' => $nonce_str,
                'out_trade_no' => $out_trade_no,
                'out_refund_no' => $out_refund_no,
                'total_fee' => intval(Tools::bcCalculate($total_fee, 100,'*')),
                'refund_fee' => intval(Tools::bcCalculate(floatval($refund_fee),100,'*')),
                "notify_url" => $notify_url,
            );
            $unifiedorder['sign'] = $this->sign($unifiedorder,1);
            $opUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
            //请求数据
            $postStr = $this->curl_post_ssl_refund($opUrl, $this->array2xml($unifiedorder));
            if ($postStr) {
                $rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                return $rs;
            } else {
                return false;
            }
        }else{
            return false;
        }
    }

    function tixian($money,$openid, $desc= '佣金提现'){

        $config = config('pament');

        $ip = Tools::get_client_ip();
        //统一下单退款参数构造
        $unifiedorder = array(
            'mch_appid' => config('program.AppID'),
            'mchid' => $config['wechat_tixian_mchids'],
            'nonce_str' => getRandom(32, "0123456789"),
            'partner_trade_no' => '1298016501' . date("Ymd") . rand(10000, 90000) . rand(10000, 90000),//商户订单号
            'openid' => $openid,
            'check_name' => 'NO_CHECK',
            'amount' => $money * 100,
            'desc' => $desc,
            'spbill_create_ip' => $ip,
        );

        $unifiedorder['sign'] = $this->sign($unifiedorder, 3);
        $var = Tools::arrayToXml($unifiedorder);
        $postStr = $this->tixian_curl_post_ssl('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', $var, 30, array(), 1);
        if ($postStr) {
            $rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            Log::write($rs, 'tixian');

            if ($rs['return_code'] == 'SUCCESS' && $rs['result_code'] == 'SUCCESS') {
                return $rs;
            }
            return false;
        } else {
            return false;
        }
    }


    function hongbaoTixian($money,$openid){

        $config = config('pament');

        $ip = Tools::get_client_ip();
        //统一下单退款参数构造
        $unifiedorder = array(
            'mch_appid' => config('program.AppID'),
            'mchid' => $config['wechat_tixian_mchids'],
            'nonce_str' => getRandom(32, "0123456789"),
            'partner_trade_no' => '1298016501' . date("Ymd") . rand(10000, 90000) . rand(10000, 90000),//商户订单号
            'openid' => $openid,
            'check_name' => 'NO_CHECK',
            'amount' => $money * 100,
            'desc' => "红包提现",
            'spbill_create_ip' => $ip,
        );

        $unifiedorder['sign'] = $this->sign($unifiedorder, 3);
        $var = Tools::arrayToXml($unifiedorder);
        $postStr = $this->tixian_curl_post_ssl('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', $var, 30, array(), 1);
        if ($postStr) {
            $rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            Log::write($rs, 'tixian');

            if ($rs['return_code'] == 'SUCCESS' && $rs['result_code'] == 'SUCCESS') {
                return $rs;
            }
            return false;
        } else {
            return false;
        }
    }

    /**
     * 付款给商户小程序用户
     * @param float money    金额
     * @param string openid  小程序openid
     * @param string  desc   支付描述
     * @return array
     * @throws exception
     */
    public function masterAppPay($money,$openid, $desc = '商户返佣'){

        $config = config('pament');
        $ip = Tools::get_client_ip();
        $appid = config('program.masterAppID');

        if(!self::checkMchPay($money, $openid, $appid, 2, $desc)){
            return false;
        }
        //统一下单退款参数构造
        $unifiedorder = array(
            'mch_appid' => $appid,
            'mchid' => $config['wechat_tixian_mchids'],
            'nonce_str' => getRandom(32, "0123456789"),
            'partner_trade_no' => '1298016501' . date("Ymd") . rand(10000, 90000) . rand(10000, 90000),//商户订单号
            'openid' => $openid,
            'check_name' => 'NO_CHECK',
            'amount' => $money * 100,
            'desc' => $desc,
            'spbill_create_ip' => $ip,
        );

        $unifiedorder['sign'] = $this->sign($unifiedorder, 3);
        $var = Tools::arrayToXml($unifiedorder);
        $postStr = $this->tixian_curl_post_ssl('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', $var, 30, array(), 1);
        if ($postStr) {
            $rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            Log::write(['result' => $rs, 'params' => $unifiedorder], 'tixian');

            if ($rs['return_code'] == 'SUCCESS' && $rs['result_code'] == 'SUCCESS') {
                return $rs;
            }
            return false;
        } else {
            return false;
        }
    }


    /**
     * 校验微信商户付款支付
     * @param float   amount 金额
     * @param string  openid 用户openid
     * @param string  appid  支付关联的appid
     * @param int     type   支付关联的类型（1公众号，2小程序）
     * @return bool
     * @throws exception
     */
    public static function checkMchPay($amount, $openid, $appid, $type, $desc){
            try{
                self::checkMchPayAmount($amount);
                self::checkMchPayOneUserTimes($openid, $appid, $type);
            }catch(\Exception $e){
                throw new \Exception($desc . '失败-' . $e->getMessage());
            }
            return true;
    }

    /**
     * 校验微信商户支付金额
     * @param float amount 支付金额
     * @return bool
     * @throws exception
     */
    private static function checkMchPayAmount($amount){
         if($amount > self::$WECHAT_PAY_CONFIG['max_amount']){
            throw new \Exception('操作金额必须小于-' . self::$WECHAT_PAY_CONFIG['max_amount'] . '元');
         }
         if($amount < self::$WECHAT_PAY_CONFIG['min_amount']){
            throw new \Exception('操作金额必须大于-' . self::$WECHAT_PAY_CONFIG['min_amount'] . '元');
         }
         return true;
    }

    /**
     * 校验单个用户一天的支付次数
     */
    private static function checkMchPayOneUserTimes($openid, $appid, $type){
        $times = self::getMchPayTimes($openid, $appid, $type);
        if($times >= self::$WECHAT_PAY_CONFIG['max_times']){
            throw new \Exception('当天最大操作次数' . self::$WECHAT_PAY_CONFIG['max_times'] . '次');
        }
        return true;
    }

    /**
     * 获取单个用户一天的支付次数
     */
    private static function getMchPayTimes($openid, $appid, $type){
        $cache_key = 'mch_pay_times' . $openid . $appid. $type;
        return Cache::get($cache_key, 0);
    }

    /**
     * 单个用户新增支付次数
     */
    private static function setMchPayTimesInc($openid, $appid, $type){
        $cache_key = 'mch_pay_times' . $openid . $appid. $type;
        if(Cache::has($cache_key)){
            return Cache::inc($cache_key);
        }
        return Cache::set($cache_key, 1, 3600*24);
    }



    function payfind($out_trade_no)
    {

        $config = config('pament');

        $ip = Tools::get_client_ip();
        //统一下单退款参数构造
        $unifiedorder = array(
            'appid' => config('pament.wechat_program_appid'),
            'mch_id' => $config['wechat_mchids'],
            'nonce_str' => getRandom(32, "0123456789"),
            'out_trade_no' => $out_trade_no,
//            'out_refund_no' => $out_refund_no,
        );
        $unifiedorder['sign'] = $this->sign($unifiedorder, 1);
        $opUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
        //请求数据
        $postStr = $this->curl_post_ssl_refund($opUrl, $this->array2xml($unifiedorder));
        if ($postStr) {
            $rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            if (isset($rs['result_code']) && $rs['result_code'] == 'SUCCESS' && isset($rs['trade_state']) && $rs['trade_state'] == 'SUCCESS') {
                $Order = \app\model\ReachOrder::where('tradeNo', $rs['out_trade_no'])->find();
                $paydate = substr($rs['time_end'], 0, 4) . '-' . substr($rs['time_end'], 4, 2) . '-' . substr($rs['time_end'], 6, 2) . ' ' . substr($rs['time_end'], 8, 2) . ":" . substr($rs['time_end'], 10, 2) . ":" . substr($rs['time_end'], 12, 2);
                if ($Order['status'] == 1) {
                    return true;
                }
                Db::startTrans();
                try {
                    $saveData['payTime'] = strtotime($paydate) ;
                    $saveData['payType'] = 1;
                    $saveData['payTradeNo'] = $rs['transaction_id'];
                    $saveData['status'] = 1;
                    $saveData['payMoney'] = $rs['total_fee'];
                    $saveData['orderNum'] = getOrderNum();
                    //更改支付状态
                    $saveOrder = $Order->where('tradeNo', $rs['out_trade_no'])->update($saveData);
                    if ($saveOrder) {
                        Db::commit();
                    }
                } catch (\Exception $e) {
                    Db::rollback();
                }
                return $rs;
            }
        } else {
        }
    }

    function masterPay($money,$openid, $desc = '商户返佣'){
        $config = config('pament');
        $ip = Tools::get_client_ip();
        //统一下单退款参数构造
        $unifiedorder = array(
            'mch_appid' => config('program.masterAppID'),
            'mchid' => $config['wechat_tixian_mchids'],
            'nonce_str' => getRandom(32, "0123456789"),
            'partner_trade_no' => '1298016501' . date("Ymd") . rand(10000, 90000) . rand(10000, 90000),//商户订单号
            'openid' => $openid,
            'check_name' => 'NO_CHECK',
            'amount' => $money * 100,
            'desc' => $desc,
            'spbill_create_ip' => $ip,
        );

        $unifiedorder['sign'] = $this->sign($unifiedorder, 3);
        $var = Tools::arrayToXml($unifiedorder);
        $postStr = $this->tixian_curl_post_ssl('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', $var, 30, array(), 1);
        if ($postStr) {
            $rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            Log::write(['result' => $rs, 'params' => $unifiedorder], 'tixian');

            if ($rs['return_code'] == 'SUCCESS' && $rs['result_code'] == 'SUCCESS') {
                return $rs;
            }
            return false;
        } else {
            return false;
        }
    }
}
